package cn.liit.weixin.message.process;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;

import name.zbq.bush.common.converter.xml.XStreamXmlMessageConverter;
import name.zbq.bush.exception.HttpConnectionException;
import name.zbq.bush.receive.handler.ServletReceiveHandler;
import name.zbq.bush.utils.RequestParse;
import name.zbq.bush.utils.StringUtil;
import cn.liit.weixin.message.model.req.ClickEventMessage;
import cn.liit.weixin.message.model.req.ImageMessage;
import cn.liit.weixin.message.model.req.LinkMessage;
import cn.liit.weixin.message.model.req.LocationMessage;
import cn.liit.weixin.message.model.req.ReqBaseMessage;
import cn.liit.weixin.message.model.req.ScanEventMessage;
import cn.liit.weixin.message.model.req.ScanSubscribeEventMessage;
import cn.liit.weixin.message.model.req.ShortVideoMessage;
import cn.liit.weixin.message.model.req.SubscribeUnsubscribeEventMessage;
import cn.liit.weixin.message.model.req.TemplateSendJobFinishMessage;
import cn.liit.weixin.message.model.req.TextMessage;
import cn.liit.weixin.message.model.req.VideoMessage;
import cn.liit.weixin.message.model.req.ViewEventMessage;
import cn.liit.weixin.message.model.req.VoiceMessage;
import cn.liit.weixin.message.model.resp.MusicMessage;
import cn.liit.weixin.message.model.resp.NewsMessage;
import cn.liit.weixin.message.model.resp.RespBaseMessage;
import cn.liit.weixin.message.model.resp.TransferCustomerServiceMessage;
import cn.liit.weixin.message.process.receive.ReceiveProcessor;
import cn.liit.weixin.message.process.receive.ReceiveProcessorManager;
import cn.liit.weixin.message.type.EventType;
import cn.liit.weixin.message.type.ReqMessageType;
/**
 * 请求消息处理
 * @author mypc
 *
 */
public class WeixinServletReceiveHandler extends ServletReceiveHandler<ReqBaseMessage, RespBaseMessage>{
	
	private final List<String> receiveList = Collections.synchronizedList(new ArrayList<String>());

    private final ThreadLocal<String> currentReceiveKey = new ThreadLocal<>();
    
    private XStreamXmlMessageConverter messageConverter;
    
	public WeixinServletReceiveHandler() {
		super();
		messageConverter = new XStreamXmlMessageConverter();
		messageConverter.processAnnotations(new Class[]{
				cn.liit.weixin.message.model.resp.ImageMessage.class,
				MusicMessage.class,
				NewsMessage.class,
				cn.liit.weixin.message.model.resp.TextMessage.class,
				TransferCustomerServiceMessage.class,
				cn.liit.weixin.message.model.resp.VideoMessage.class,
				cn.liit.weixin.message.model.resp.VoiceMessage.class});
	}

	@Override
	public ReqBaseMessage doInput(InputStream inputStream){
		ReqBaseMessage reqBaseMessage = null;
		try {
			Map<String,String> dataMap = RequestParse.parseInputStream(inputStream,false);
			String msgType = dataMap.get("msgType");
			reqBaseMessage = null;
			//文本消息
			if (msgType.equals(ReqMessageType.REQ_MESSAGE_TYPE_TEXT.getType())) {
				reqBaseMessage = new TextMessage();
			} 
			// 图片消息  
			else if (msgType.equals(ReqMessageType.REQ_MESSAGE_TYPE_IMAGE.getType())) {  
				reqBaseMessage = new ImageMessage();
			}
			// 语音消息  
			else if (msgType.equals(ReqMessageType.REQ_MESSAGE_TYPE_VOICE.getType())) {
				reqBaseMessage = new VoiceMessage();
			}
			// 视频消息
			else if (msgType.equals(ReqMessageType.REQ_MESSAGE_TYPE_VIDEO.getType())) {
				reqBaseMessage = new VideoMessage();
			}
			// 小视频消息
			else if(msgType.equals(ReqMessageType.REQ_MESSAGE_TYPE_SHORTVIDEO.getType())){
				reqBaseMessage = new ShortVideoMessage();
			}
			// 地理位置消息  
			else if (msgType.equals(ReqMessageType.REQ_MESSAGE_TYPE_LOCATION.getType())) {
				reqBaseMessage = new LocationMessage();
			}
			// 链接消息  
			else if (msgType.equals(ReqMessageType.REQ_MESSAGE_TYPE_LINK.getType())) {
				reqBaseMessage = new LinkMessage();
			}
			//事件推送
			else if (msgType.equals(ReqMessageType.REQ_MESSAGE_TYPE_EVENT.getType())) {
				//获取事件类型
				String eventType = dataMap.get("event");
				if(eventType.equals(EventType.EVENT_TYPE_SUBSCRIBE.getType())){
					//扫码时间携带的eventKey(qrscene_123123)
					String eventKey = dataMap.get("eventKey");
					//判断是否存在eventkey 未关注状态下扫码关注后的推送
					if(!StringUtil.isEmpty(eventKey)){
						reqBaseMessage = new ScanSubscribeEventMessage();
					}else{//关注事件
						reqBaseMessage = new SubscribeUnsubscribeEventMessage();
					}
				}else if(eventType.equals(EventType.EVENT_TYPE_UNSUBSCRIBE.getType())){//取消关注
					reqBaseMessage = new SubscribeUnsubscribeEventMessage();
				}else if(eventType.equals(EventType.EVENT_TYPE_CLICK.getType())){//自定义菜单拉取信息事件
					reqBaseMessage = new ClickEventMessage();
				}else if(eventType.equals(EventType.EVENT_TYPE_VIEW.getType())){//自定义菜单跳转链接事件
					reqBaseMessage = new ViewEventMessage();
				}else if(eventType.equals(EventType.EVENT_TYPE_LOCATION.getType())){
					/*	
 						String latitude = dataMap.get("Latitude");//获取地理位置维度
						String longitude = dataMap.get("Longitude");//获取地理位置经度
						String precision = dataMap.get("Precision");//获取地理位置精度
					*/
					reqBaseMessage = new LocationMessage();
				}else if(eventType.equals(EventType.EVENT_TYPE_SCAN.getType())){//已关注情况下的扫码事件
					reqBaseMessage = new ScanEventMessage();
				}else if(eventType.equals(EventType.EVENT_TYPE_TEMPLATESENDJOBFINISH.getType())){// 模版消息发送结束通知
					reqBaseMessage = new TemplateSendJobFinishMessage();
				}
			}
			BeanUtils.copyProperties(reqBaseMessage, dataMap);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return reqBaseMessage;
	}
	
	@Override
    public RespBaseMessage onHandlerMessage(ReqBaseMessage inputData) {
        //消息去重
        if (inputData == null) {
            return null;
        }

        String receiveKey = inputData.getFromUserName() + inputData.getCreateTime();
        synchronized (receiveList) {
            if (receiveList.contains(receiveKey)) {
                return null;
            } else {
                receiveList.add(receiveKey);
                currentReceiveKey.set(receiveKey);
            }
        }

        ReceiveProcessor receiveProcessor = ReceiveProcessorManager.getMsgProcessor(inputData);
        
        if (receiveProcessor == null) {
            return null;
        }

        RespBaseMessage response = receiveProcessor.doProcess(inputData);

        if (response != null) {
            response.setFromUserName(inputData.getToUserName());
            response.setToUserName(inputData.getFromUserName());
            response.setCreateTime(String.valueOf(new Date().getTime()));
        }

        return response;
    }

	@Override
	public void doOutput(OutputStream outputStream, RespBaseMessage respData) {
		if(messageConverter.canWrite(respData.getClass())){
			messageConverter.write(respData, outputStream);
		}else{
			throw new HttpConnectionException("Unable write request data with class " + respData.getClass());
		}
	}
	
	@Override
	public void onReceiveFinish() {
		String receiveKey = currentReceiveKey.get();
        if (StringUtil.hasText(receiveKey)) {
            synchronized (receiveList) {
            	receiveList.remove(receiveKey);
            }
        }
	}
	
}
